package manager.pay;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;


import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;


import org.springframework.beans.BeansException;

import com.fasterxml.jackson.core.JsonProcessingException;

import alisms.SmsDemo;
import database.DBService;
import database.UserConsumeDBServer;
import database.UserRechargeDBServer;
import database.pojo.UserConsumeInfo;
import database.pojo.UserRechargeInfo;
import javassist.expr.NewArray;
import manager.connection.ClientConnectionManager;
import manager.connection.type.GMOrderInfo;
import manager.pay.state.ConsumptionType;
import manager.pay.state.PayState;
import manager.pay.type.EndTimeInfo;
import manager.pay.type.PayResultInfo;
import manager.pay.type.ntfPlayerPayStatusInfo;
import manager.pay.type.ntfWeChatPayInfo;
import manager.player.PlayerManager;
import net.socket.server.SocketServer;
import net.socket.server.protocal.PROTOID;
import net.socket.server.request.IRequest;
import net.socket.server.request.PlayerLogoutRequest;
import net.socket.server.response.NTFVipGradeResponse;
import util.MyFactory;

/**
 * 类名：GetPayResult
 * 描述：处理支付回调,并通知客户端玩家时间over
 * @date 2018-4-24
 * @author zk
 * @version 0.0.1
 *
 */
public class GetPayResult {
	private ClientConnectionManager ccm = null;
	private PlayerManager pm = null;
	private Map<String, EndTimeInfo>  endTimeMap = new HashMap<String,EndTimeInfo>();
	
	private ArrayList<URI> ntfPHPFailList = new ArrayList<URI>();
	
	public void init(){
		ccm = MyFactory.context.getBean("ClientConnectionManager", ClientConnectionManager.class);
		pm = MyFactory.context.getBean("PlayerManager", PlayerManager.class);
		
		Timer timer = new Timer();
		TimerTask taskClient =ntfClient();
		TimerTask taskPHP = ntfPHP();
		
		timer.schedule(taskClient,0, 5000);
		timer.schedule(taskPHP, 0, 1000*60*60*3);
	}
	
	
	private TimerTask ntfPHP() {
		TimerTask task = new TimerTask() {			
			@Override
			public void run() {
				if(!ntfPHPFailList.isEmpty()) {
					Iterator<URI> it = ntfPHPFailList.iterator();
					while(it.hasNext()) {
						URI uri =it.next();
							try {
								if(ntfPHPFail(uri)) {
									synchronized (ntfPHPFailList) {
										it.remove();
									}
								}else {
									synchronized(ntfPHPFailList) {
										ntfPHPFailList.add(uri);
										break;
									}
								}
							} catch (IOException e) {
								System.out.println("ntfPHP GET IOException:"+e);	
							}														
					}
					
				}
			}
		};
		return task;
	}

	private boolean ntfPHPFail(URI uri) throws IOException {
		 CloseableHttpClient httpclient = HttpClients.createDefault();
		 HttpGet httpGet = new HttpGet(uri);
	        //response 对象
	        CloseableHttpResponse response = null;
	        try {  
				response = httpclient.execute(httpGet);
	        }catch (IOException e) {
	        	System.out.println("ntfPHPFail get IOException:" +e);
	        	return false;
	        } finally {
	            if (response != null) {
	                response.close();
	            }
	            httpclient.close();
	        }
	        return true;
		
	}	
	
	private TimerTask  ntfClient() {
		TimerTask task = new TimerTask() {
			
		@Override
		public void run() {
			if(endTimeMap.size() !=0) {
				try {
					ntfClientTimeOver();
				} catch (IllegalArgumentException | IllegalAccessException | JsonProcessingException e) {
					System.out.println("ntfClientGameOver have a Exception:"+e);
				}
			}
		}	
		};
		return task;
		
	}
	
	
	private void ntfClientTimeOver() throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		EndTimeInfo eInfo =null;
		Iterator<Entry<String, EndTimeInfo>> entries = endTimeMap.entrySet().iterator();  
		  
		while (entries.hasNext()) {  
		  Map.Entry<String, EndTimeInfo> entry = entries.next();   
		  eInfo = entry.getValue(); 
		  if(eInfo.getEndTime() <= System.currentTimeMillis()) {
			synchronized(endTimeMap) {
				  entries.remove(); 
			 }
			if(eInfo.getOpenId().equals(ccm.getOpenIdByMachine(eInfo.getMid())))
				  ccm.sendResponse(PROTOID.NTF_TIME_IS_OVER, eInfo.getMid(), eInfo);
			MyFactory.context.getBean("DBService", DBService.class).updateEndtime(eInfo.getOpenId(),0,0);			  											  
		  }
		  
		}
	}	

	public void insetUserConsume(UserRechargeInfo rsp) throws BeansException, SQLException {
		UserConsumeInfo uInfo = new UserConsumeInfo();
		
		uInfo.setMid(rsp.getMid());
		uInfo.setUid(rsp.getUid());
		uInfo.setMount(rsp.getMount());
		uInfo.setDescription(rsp.getRecharge_description());
		uInfo.setOrder_sn(rsp.getRecharge_orderid());
		uInfo.setOrder_type(rsp.getRecharge_type());
		uInfo.setPay_time(rsp.getRecharge_time());
		uInfo.setStatus(rsp.getRecharge_status());
		
		MyFactory.context.getBean("UserConsumeDBServer",UserConsumeDBServer.class).insertUserConsume(uInfo);
		
	}

	public void ntfPHPServer(PayResultInfo req) throws BeansException, SQLException, URISyntaxException, IOException {
		// 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();
        ntfWeChatPayInfo rsp = new ntfWeChatPayInfo();
        rsp.setMid(Integer.toString(req.getMachineId()));
        rsp.setMoney(String.format("%.2f", req.getPrice()));
        rsp.setOrder_sn(req.getOut_trade_no()); 
        rsp.setUid(Integer.toString(MyFactory.context.getBean("DBService", DBService.class).getUidByOpenId(req.getOpenId())));
        if(rsp.getUid().equals("0")) {
        	rsp.setUid(Integer.toString(MyFactory.context.getBean("UserRechargeDBServer", UserRechargeDBServer.class)
        			.selectUid(req.getOut_trade_no())));
        	System.out.println("ntfPHPServer res.getuid:"+rsp.getUid());
        }
        //URI uri = new URIBuilder("http://14.119.109.232:30666/center/finance?")
        URI uri = new URIBuilder("http://"+SocketServer.adress+":30666/center/finance?")//测试环境
        		.addParameter("cmd", "update_finance")
        		.addParameter("out_trade_no", rsp.getOrder_sn())
        		.addParameter("money", rsp.getMoney())
        		.addParameter("mid", rsp.getMid())
        		.addParameter("uid", rsp.getUid())
        		.build();
        
        HttpGet httpGet = new HttpGet(uri);
        //response 对象
        CloseableHttpResponse response = null;
        try {
            // 执行http get请求
            try {
				response = httpclient.execute(httpGet);
			} catch (IOException e) {
				e.printStackTrace();
				synchronized(ntfPHPFailList) {
					ntfPHPFailList.add(uri);
				}
			}
        } finally {
            if (response != null) {
                response.close();
            }
            httpclient.close();
        }
		
	}
	public void putMap(String openId,EndTimeInfo eTimeInfo) {
		synchronized(endTimeMap) {
			endTimeMap.put(openId, eTimeInfo);
		}
	}
	
	public void removeMap(String openId) {
		synchronized (endTimeMap) {
			endTimeMap.remove(openId);
		}
	}
	
	public void removeWhileOtherMid(String openId,int mid) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		if("".equals(openId)||mid<1)
			return;
		EndTimeInfo eInfo = getMap(openId);
		int machineId=-1;
		if(eInfo==null) {
			machineId= ccm.getMachineIdByOpenId(openId);//如果再充值队列里没找到，再看看是否再机器队列里
			if(machineId==-1)//不在
				return;
			System.out.println("The user in mid:"+machineId);
			if(machineId!=mid) {//如果用户在其它机器上登录还没有退出
				PlayerLogoutRequest req= new PlayerLogoutRequest();
				req.setMachineId(machineId);
				req.setOpenId(openId);
				ccm.handlePlayLogout(PROTOID.PLAYER_LOGOUT_REQ,(IRequest)req);
			}
			return;
		}
		if(eInfo.getMid()!=mid) {//如果用户在其它机器上登录还没有退出
			PlayerLogoutRequest req= new PlayerLogoutRequest();
			req.setMachineId(eInfo.getMid());
			req.setOpenId(openId);
			ccm.handlePlayLogout(PROTOID.PLAYER_LOGOUT_REQ,(IRequest)req);
			removeMap(openId);
			
		}
	}
	
	private EndTimeInfo getMap(String openId) {
			return endTimeMap.get(openId);
		
	}	
	public boolean isExitOrderSnAndPaySucc(String out_trade_no) throws BeansException, SQLException {
		return MyFactory.context.getBean("UserRechargeDBServer", UserRechargeDBServer.class).isExitOrderSnAndPaySucc(out_trade_no);
	}

	public PayResultInfo outTrafeNoToPayResultInfo(String outTradeNo) throws BeansException, SQLException {
		PayResultInfo req = new PayResultInfo();
		req = MyFactory.context.getBean("UserRechargeDBServer", UserRechargeDBServer.class).getPayResultInfo(outTradeNo);
		req.setkCoin((int)req.getPrice()*10);
		req.setResult("true");
		
		req.setOpenId(ccm.getOpenIdByMachine(req.getMachineId()));
		
		return req;
	}

	/**
	 * 根据支付回调的信息更新用户充值表，只需要更新支付状态，支付时间
	 * @param rsp
	 * @return
	 * @throws SQLException 
	 * @throws BeansException 
	 */
	public UserRechargeInfo updateUserRecharge(PayResultInfo rsp) throws BeansException, SQLException {
		UserRechargeInfo uInfo = new UserRechargeInfo();
	
		Calendar calendar = Calendar.getInstance();
    	int year = calendar.get(Calendar.YEAR);
    	int month = calendar.get(Calendar.MONTH) + 1;
    	int date = calendar.get(Calendar.DATE);
    	int hour = calendar.get(Calendar.HOUR_OF_DAY);
    	int minute = calendar.get(Calendar.MINUTE);
    	int second  =calendar.get(Calendar.SECOND);
    	String recharge_day =year+"-"+month+"-"+date;
    	String Recharge_time =year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second;
    	//只需更新此3个
		uInfo.setRecharge_day(recharge_day);
		uInfo.setRecharge_status(PayState.PAYSUCC);//充值状态,1成功
		uInfo.setRecharge_time(Recharge_time);//充值时间
		uInfo.setRecharge_orderid(rsp.getOut_trade_no());
		MyFactory.context.getBean("UserRechargeDBServer", UserRechargeDBServer.class).updateUserRecharge(uInfo);
		
		
		uInfo.setMid(rsp.getMachineId());
		uInfo.setMount(rsp.getPrice());
		uInfo.setRecharge_type(rsp.getTradeid());//充值类型.1微信,2.支付宝
		uInfo.setUid(MyFactory.context.getBean("DBService", DBService.class).getUidByOpenId(rsp.getOpenId()));
		uInfo.setRecharge_description(rsp.getRecharge_description());
		
		return uInfo;
	}

	public void ntfVipGradeChange(NTFVipGradeResponse rsp, int mid) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		 ccm.sendResponse(PROTOID.NTF_VIP_CHANGE, mid, rsp);
		 pm.setPlayerVipGrader(ccm.getOpenIdByMachine(mid), rsp.getVipGrade());
		
	}
	
	public void ntfPlayerPayStatus(PayResultInfo req, int consumptionType, int minites) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException, BeansException, SQLException {
		if(consumptionType ==ConsumptionType.BUYKCOIN) {
			ntfPayBuyKcoin(req,minites);
		}else if(consumptionType ==ConsumptionType.KCOINCONSUMED) {
			ntfPayKcoinCon(req,minites);
		}else if (consumptionType == ConsumptionType.BUYPACKET) {
			ntfFPayOfBuyPacket(req,minites);
		}else {
			System.out.println("UNKWON consumptionType");
		}		
	}

	private void ntfPayBuyKcoin(PayResultInfo req, int minites) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException, BeansException, SQLException {
		//System.out.println("ntfPayBuyKcoin-------");
		ntfPlayerPayStatusInfo rsp = new ntfPlayerPayStatusInfo();
		//String openId = ccm.getOpenIdByMachine(req.getMachineId());
		int beforeKCoin = MyFactory.context.getBean("DBService", DBService.class).getKCodeByOpenId(req.getOpenId());
		System.out.println("beforeKCoin:"+beforeKCoin);
		System.out.println("ntfPayBuyKcoin req.getkCoin():"+req.getkCoin());
		int allKCoin =beforeKCoin+req.getkCoin();//充值k币的话就需要先查看用户有多少k币，然后在更新
		MyFactory.context.getBean("DBService", DBService.class).updateKCoin(req.getOpenId(), allKCoin);
			
		double beforeAllConsume,afterAllConsume;
		if(ClientConnectionManager.allConsume.containsKey(req.getOpenId())) {
				beforeAllConsume = ClientConnectionManager.allConsume.get(req.getOpenId());
		}else {
				beforeAllConsume =0;
		}
		afterAllConsume = beforeAllConsume +req.getPrice();
		System.out.println("afterAllConsume:"+afterAllConsume);
		ClientConnectionManager.allConsume.put(req.getOpenId(), afterAllConsume);
		MyFactory.context.getBean("DBService", DBService.class).updateAllConsume(afterAllConsume,req.getOpenId());
			
		System.out.println("allKCoin:"+allKCoin);
		rsp.setkCoin(allKCoin);
		rsp.setConsumptionType(ConsumptionType.BUYKCOIN);
		ccm.sendResponse(PROTOID.NTF_PLAYER_PAY_STATUS, req.getMachineId(), rsp);
		String mess = "购买k币";
		//支付成功通知管理员
	    //String sms_code="SMS_139226591";
	    //String mess = String.format("{\"city\":%s, \"nickname\":%s,\"type\":%s,\"money\":%s,\"trade\":%s}",userInfo.getCity(),userInfo.getNickName()) ;
		//SmsDemo.sendSms(messid,mess);
			
	}

	private void ntfPayKcoinCon(PayResultInfo req, int minites) throws BeansException, SQLException, IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		ntfPlayerPayStatusInfo rsp = new ntfPlayerPayStatusInfo();
		String openId = ccm.getOpenIdByMachine(req.getMachineId());
		int beforeKCoin=0;
		try {
			beforeKCoin = MyFactory.context.getBean("DBService", DBService.class).getKCodeByOpenId(req.getOpenId());
		} catch (BeansException | SQLException e) {
			e.printStackTrace();
		}
		System.out.println("beforeKCoin:"+beforeKCoin);
		System.out.println("ntfPayKcoinCon req.getkCoin():"+req.getkCoin());
		int allKCoin =beforeKCoin-req.getkCoin();
		MyFactory.context.getBean("DBService", DBService.class).updateKCoin(req.getOpenId(), allKCoin);
		System.out.println("allKCoin:"+allKCoin);
		long endTime;
		int palyerSecond=minites * 60*1000;//一共有多少豪秒的游戏时间
		long currentTime = System.currentTimeMillis();
		endTime =palyerSecond+currentTime;
		EndTimeInfo eTimeInfo =getMap(openId);
		if (null ==eTimeInfo) {
			//System.out.println("eTimeInfo is null");
			eTimeInfo = new EndTimeInfo();
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(req.getMachineId());
			eTimeInfo.setOpenId(openId);
			
		} else {
			//System.out.println("eTimeInfo is not null");
			endTime = endTime+eTimeInfo.getEndTime()-currentTime;
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(req.getMachineId());
			eTimeInfo.setOpenId(openId);
		}
		putMap(openId, eTimeInfo);
		rsp.setEndTime(endTime);
		rsp.setEndTime(endTime);
		rsp.setkCoin(allKCoin);
		MyFactory.context.getBean("DBService", DBService.class).updateEndtime(openId, endTime,minites);
		rsp.setConsumptionType(ConsumptionType.KCOINCONSUMED);
		ccm.sendResponse(PROTOID.NTF_PLAYER_PAY_STATUS, req.getMachineId(), rsp);
		
	}

	private void ntfFPayOfBuyPacket(PayResultInfo req, int minites) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		ntfPlayerPayStatusInfo rsp = new ntfPlayerPayStatusInfo();
		String openId = ccm.getOpenIdByMachine(req.getMachineId());
		int beforeKCoin =0;
		try {
			beforeKCoin = MyFactory.context.getBean("DBService", DBService.class).getKCodeByOpenId(req.getOpenId());
		} catch (BeansException | SQLException e1) {
			e1.printStackTrace();
		}
		System.out.println("beforeKCoin:"+beforeKCoin);
		rsp.setkCoin(beforeKCoin);//只需查找有多少k币，因为购买套餐之后得到的k币是马上消费了的
		rsp.setConsumptionType(ConsumptionType.BUYPACKET);
		long endTime;
		int palyerSecond=minites * 60*1000;//一共有多少豪秒的游戏时间
		//时间累加
		long currentTime = System.currentTimeMillis();
		endTime =palyerSecond+currentTime;
		EndTimeInfo eTimeInfo =getMap(openId);
		if (null ==eTimeInfo) {
			//System.out.println("eTimeInfo is null");
			eTimeInfo = new EndTimeInfo();
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(req.getMachineId());
			eTimeInfo.setOpenId(openId);
			
		} else {
			//System.out.println("eTimeInfo is not null");
			endTime = endTime+eTimeInfo.getEndTime()-currentTime;
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(req.getMachineId());
			eTimeInfo.setOpenId(openId);
		}
		putMap(openId, eTimeInfo);
		rsp.setEndTime(endTime);
		ccm.sendResponse(PROTOID.NTF_PLAYER_PAY_STATUS, req.getMachineId(), rsp);
		double beforeAllConsume,afterAllConsume;
		if(ClientConnectionManager.allConsume.containsKey(req.getOpenId())) {
			beforeAllConsume = ClientConnectionManager.allConsume.get(req.getOpenId());
		}else {
			beforeAllConsume =0;
		}
		afterAllConsume = beforeAllConsume +req.getPrice();
		System.out.println("afterAllConsume:"+afterAllConsume);
		ClientConnectionManager.allConsume.put(req.getOpenId(), afterAllConsume);
	
		MyFactory.context.getBean("DBService", DBService.class).updateEndtimeAndAllConsume(openId,endTime,afterAllConsume,minites);
			
	}


	public void setVip(GMOrderInfo gOrderInfo) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException, BeansException, SQLException {
		System.out.println("setVip:");
		NTFVipGradeResponse rsp = new NTFVipGradeResponse();
		rsp.setVipGrade(gOrderInfo.getNum());
		MyFactory.context.getBean("DBService", DBService.class).
		updateVipGrade(gOrderInfo.getNum(), ccm.getOpenIdByMachine(gOrderInfo.getMid()));
		ccm.sendResponse(PROTOID.NTF_VIP_CHANGE, gOrderInfo.getMid(), rsp);
		pm.setPlayerVipGrader(ccm.getOpenIdByMachine(gOrderInfo.getMid()), gOrderInfo.getNum());
		
	}


	public void getCion(GMOrderInfo gOrderInfo) throws BeansException, SQLException, IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		System.out.println("getCion:");
		ntfPlayerPayStatusInfo rsp = new ntfPlayerPayStatusInfo();
		String openId = ccm.getOpenIdByMachine(gOrderInfo.getMid());
		int beforeKCoin = MyFactory.context.getBean("DBService", DBService.class).getKCodeByOpenId(openId);
		System.out.println("GM getCion-beforeKCoin:"+beforeKCoin);
		System.out.println("GM gOrderInfo.getNum():"+gOrderInfo.getNum());
		int allKCoin =beforeKCoin+gOrderInfo.getNum();//充值k币的话就需要先查看用户有多少k币，然后在更新
		MyFactory.context.getBean("DBService", DBService.class).updateKCoin(openId, allKCoin);
		System.out.println("GM allKCoin:"+allKCoin);
		rsp.setkCoin(allKCoin);
		rsp.setConsumptionType(ConsumptionType.BUYKCOIN);
		ccm.sendResponse(PROTOID.NTF_PLAYER_PAY_STATUS,gOrderInfo.getMid(), rsp);
		
	}


	public void getTime(GMOrderInfo gOrderInfo) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException, BeansException, SQLException {
		System.out.println("getTime:");
		ntfPlayerPayStatusInfo rsp = new ntfPlayerPayStatusInfo();
		long endTime;
		String openId = ccm.getOpenIdByMachine(gOrderInfo.getMid());
		int palyerSecond=gOrderInfo.getNum() * 60*1000;//一共有多少豪秒的游戏时间
		long currentTime = System.currentTimeMillis();
		endTime =palyerSecond+currentTime;
		EndTimeInfo eTimeInfo =getMap(openId);
		if (null ==eTimeInfo) {
			//System.out.println("GM eTimeInfo is null");
			eTimeInfo = new EndTimeInfo();
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(gOrderInfo.getMid());
			eTimeInfo.setOpenId(openId);
			
		} else {
			//System.out.println("GM eTimeInfo is not null");
			endTime = endTime+eTimeInfo.getEndTime()-currentTime;
			eTimeInfo.setEndTime(endTime);
			eTimeInfo.setMid(gOrderInfo.getMid());
			eTimeInfo.setOpenId(openId);
		}
		putMap(openId, eTimeInfo);
		rsp.setEndTime(endTime);
		rsp.setEndTime(endTime);
		rsp.setkCoin(0);
		rsp.setConsumptionType(ConsumptionType.KCOINCONSUMED);
		MyFactory.context.getBean("DBService",DBService.class).updateEndtime(openId, endTime,gOrderInfo.getNum());
		ccm.sendResponse(PROTOID.NTF_PLAYER_PAY_STATUS, gOrderInfo.getMid(), rsp);	
		
	}
	
}
